package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"log"
	"time"
)

// Block 区块结构体
type Block struct{
	//1.区块版本号
	Version uint64
	//2.前区块Hash
	PreBlockHash []byte
	//3.merkel根
	MerkelRoot []byte
	//4.时间戳
	TimeStamp uint64
	//5.难度值
	Difficulty uint64
	//6.随机数,也就是挖矿要找的数据
	Nonce uint64
	//a.当前区块的Hash值,在现实比特币中没有这个
	Hash []byte
	Data []byte
}
// Uint64ConvertByte 将uint64类型转换为[]byte{}类型
func Uint64ConvertByte(data uint64)[]byte{
	var buffer bytes.Buffer
	err := binary.Write(&buffer, binary.BigEndian,data)
	if err != nil {
		log.Panicln(err)
	}
	return buffer.Bytes()
}
// CreateBlock 创建block
func CreateBlock(preBlockHash []byte, data string) *Block{
	block := Block{
		Version: 00,
		PreBlockHash: preBlockHash,
		MerkelRoot: []byte{},
		TimeStamp: uint64(time.Now().Unix()),
		Difficulty: 0,//随便填一个
		Nonce: 0,//随便填一个
		Data: []byte(data),
		Hash: []byte{},
	}
	//进行挖矿,得到挖矿成功后的hash和随机值
	pow := CreatePOW(&block)
	//挖矿模拟,不断改变随机数,计算hash,直到找到合适的hash
	hash,nonce := pow.Run()
	//根据挖矿结果对区块数据不断进行更新
	block.Hash = hash
	block.Nonce = nonce
	//block.SetHash()
	return &block
}
// GenesisBlock 创建创世块，即第一个区块
func GenesisBlock() *Block{
	genesisBlock := CreateBlock([]byte{},"第一个创世块,牛逼")
	return genesisBlock
}
// SetHash 计算当前区块的hash
func (block *Block)SetHash(){
	var blockInfo []byte
	//...的作用是把data数组打散，一个个装进preBlockHash切片中
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Version)...)
	//blockInfo = append(blockInfo, block.PreBlockHash...)
	//blockInfo = append(blockInfo, block.MerkelRoot...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.TimeStamp)...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Difficulty)...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Nonce)...)
	//blockInfo = append(blockInfo, block.Data...)
	// 创建一个二维数组
	tem := [][]byte{
		Uint64ConvertByte(block.Version),
		block.PreBlockHash,
		block.MerkelRoot,
		Uint64ConvertByte(block.TimeStamp),
		Uint64ConvertByte(block.Difficulty),
		Uint64ConvertByte(block.Nonce),
		block.Data,
	}
	//将二维byte数组连接成一维byte数组
	bytes.Join(tem, []byte{})
	//hash是一个字节数组
	Hash := sha256.Sum256(blockInfo)
	//block.Hash作为Hash的切片
	block.Hash = Hash[:]
}